﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace TriangleGame
{
    public class Griglia
    {
        private Punto[] Punti;
        private List<Tupla> ADJList;
        private int nX;
        private int nY;

        public List<Tupla> getLista() { return ADJList; }
        public Punto[] getPunti() { return Punti; }
        public int getX() { return nX; }
        public int getY() { return nY; }

        public Griglia(int nX, int nY)
        {
            //creo tutti i punti
            Punti = new Punto[nX * nY];//array lungo nX*nY, vuoto
            ADJList = new List<Tupla>();//lista vuota
            this.nX = nX; //salvo numero colonne
            this.nY = nY; //salvo numero righe
            int index = 0;

            for (int i = 1; i <= nX; i++)
            {
                for (int j = 1; j <= nY; j++)
                {
                    Punti[index] = new Punto(i, j);
                    index++;
                }
            }

            //creo lista di ADJ
            //lista Tuple<PuntoA, puntoB,alfa,LinkedList>
            for (int i = 0; i < Punti.Length; i++)
            {
                for (int j = 0; j < Punti.Length; j++)
                {
                    //se i due punti sono adiacenti vengono aggiunti alla lista, niente altrimenti
                    if(!(Punti[i].Equals(Punti[j])))//sono diversi
                    {
                        ADJList.Add(new Tupla(Punti[i], Punti[j], Punti[i].CalcolaAlfa(Punti[j]), Punti[i].CalcolaDistanza(Punti[j])));
                    }
                }
            }

            ADJList.Sort();
            RemoveADJ();//forse nome poco significativo!!

        }//costruttore Griglia

        public void RemoveADJ()
        {
            foreach (Punto p in Punti)
            {
                List<double> angoli=new List<double>();

                for (int index = 0; index < ADJList.Count; index++)
                {
                    if (ADJList.ElementAt(index).getPuntoA().Equals(p))//se sono uguali
                    {
                        double angolo = ADJList.ElementAt(index).getAlfa();

                        if (angoli.Contains(angolo))//se già presente
                        {
                            //rimuovi
                            ADJList.Remove(ADJList.ElementAt(index));
                            index--;
                        }
                        else//angolo non presente
                        {
                            angoli.Add(angolo);
                        }

                    }
                    //se diversi non faccio nulla
                }//for ADJList

            }//foreach Punto
        
        }//RemoveADJ

        public bool IsInterno(Punto a, Punto b, Punto c, Punto p)
        {
            if (p.Equals(a) || p.Equals(b) || p.Equals(c))
            {
                return false;
            }
            double d1 = ((p.getX() - a.getX()) * (c.getY() - a.getY())) - ((p.getY() - a.getY()) * (c.getX() - a.getX()));
            double d2 = ((p.getX() - a.getX()) * (b.getY() - a.getY())) - ((p.getY() - a.getY()) * (b.getX() - a.getX()));
            double d3 = ((b.getX() - a.getX()) * (c.getY() - a.getY())) - ((b.getY() - a.getY()) * (c.getX() - a.getX()));
            double d4 = ((b.getY() - a.getY()) * (c.getX() - a.getX())) - ((b.getX() - a.getX()) * (c.getY() - a.getY()));
            double m = d1 / d3;
            double n = d2 / d4;

            if (m == 0 || n == 0)
                return false;
            else return (((m > 0) && (n > 0)) && (m + n < 1));
        }


        public void AggiornaADJ(Punto a, Punto b)
        {
            foreach (Punto p in Punti)
            {
                if (!(p.Equals(a) || p.Equals(b)))
                {
                    double alfapa = p.CalcolaAlfa(a); 
                    double alfapb = p.CalcolaAlfa(b);
                 
                    double angolomaggiore = System.Math.Max(alfapa, alfapb);
                    double angolominore = System.Math.Min(alfapa, alfapb);
                    for (int i = 0; i < ADJList.Count; i++)
                    {                 
                        if (ADJList[i].getPuntoA().Equals(p))
                        {
                            if (angolomaggiore - angolominore > 180)
                            {
                                if (ADJList[i].getAlfa() < angolominore || ADJList[i].getAlfa() > angolomaggiore)
                                {
                                    Punto q = ADJList[i].getPuntoB();
                                    if (!IsInterno(p, a, b, q))
                                    {
                                        ADJList.Remove(ADJList[i]);
                                        i--;
                                    }
                                }
                            }
                            else if (ADJList[i].getAlfa() > angolominore && ADJList[i].getAlfa() < angolomaggiore)
                            {
                                Punto q = ADJList[i].getPuntoB();
                                if (!IsInterno(p, a, b, q))
                                {
                                    ADJList.Remove(ADJList[i]);
                                    i--;
                                }
                            }
                        }
                    }               
                }          
            }
        }//AggironaADJ

        public void Linka(Punto a, Punto b)
        {
            foreach (Tupla t in ADJList)
            {
                if (t.getPuntoA().Equals(a) && t.getPuntoB().Equals(b))
                    t.setLinked(true);
                else if (t.getPuntoA().Equals(b) && t.getPuntoB().Equals(a))
                    t.setLinked(true);
            }
        }//Linka

        public List<Punto> TrovaTriangolo(Punto a, Punto b)
        {
            List<Punto> ls = new List<Punto>();
            foreach (Tupla t in ADJList)
            {
                if (t.getPuntoA().Equals(a) && t.getLinked() == true && !t.getPuntoB().Equals(b))
                {
                    Punto p = t.getPuntoB();

                    foreach (Tupla z in ADJList)
                    {
                        if (z.getPuntoA().Equals(p) && z.getPuntoB().Equals(b) && z.getLinked() == true)
                            ls.Add(p);
                    }
                }
            }
            foreach (Punto p in Punti)
            {
                for (int i = 0; i < ls.Count; i++)
                {
                    if (IsInterno(a, b, ls[i], p))
                    {
                        ls.Remove(ls[i]);
                        i--;
                    }
                }
            }
            return ls;
        }//TrovaTriangolo

        public double AreaTriangolo(Punto a, Punto b, Punto c)
        {
            /*int[,] matrice = new int[3,3]; //vecchio algoritmo basato su matrice
            matrice[0,0] = a.getX();
            matrice[0,1] = a.getY();
            matrice[1,0] = b.getX();
            matrice[1,1] = b.getY();
            matrice[2,0] = c.getX();
            matrice[2,1] = c.getY();
            matrice[0,2] = 1;
            matrice[1,2] = 1;
            matrice[2,2] = 1;


            double det = (matrice[0,0] * matrice[1,1] + matrice[2,2]) + (matrice[0,1] * matrice[1,2] * matrice[2,0]) + (matrice[0,2] * matrice[1,0] * matrice[2,1]) -
                         ((matrice[0,2] * matrice[1,1] * matrice[2,0]) + (matrice[0,1] * matrice[1,0] * matrice[2,2]) + (matrice[0,0] * matrice[1,2] * matrice[2,1]));

            return System.Math.Abs(det) / 2;*/

            //nuovo algoritmo basato su distanza tra i punti
            double ab = Math.Sqrt((double)(b.getX() - a.getX()) * (b.getX() - a.getX()) + (b.getY() - a.getY()) * (b.getY() - a.getY()));
            double bc = Math.Sqrt((double)(b.getX() - c.getX()) * (b.getX() - c.getX()) + (b.getY() - c.getY()) * (b.getY() - c.getY()));
            double ca = Math.Sqrt((double)(a.getX() - c.getX()) * (a.getX() - c.getX()) + (a.getY() - c.getY()) * (a.getY() - c.getY()));

            double s = (ab + bc + ca) / 2;
            return Math.Sqrt(s * (s - ab) * (s - bc) * (s - ca));

        }//AreaTriangolo

        public bool ControllaMossa(Punto a, Punto b) { //controllo se la mossa è valida
            foreach(Tupla t in ADJList){
                if (t.getPuntoA().Equals(a) && t.getPuntoB().Equals(b) && t.getLinked() == false)
                {
                    return true;
                }
                else if (t.getPuntoA().Equals(b) && t.getPuntoB().Equals(a) && t.getLinked() == false)
                {
                    return true;
                }
            }
            return false;
        } 
                    

    }//class Griglia
}